<?php
declare(strict_types=1);

namespace Service\PayService\Payer;

use Service\BaseService;
use Service\UserService\MnUserService;
use Service\ConfigureService\ChannelConfigService;
use Service\ChannelService\StoreConfigService;
use Service\VenderClient\PayCenterApi\HnapayApiClient;
use Service\Code\Normal;
use Service\MessageService\PayNotifyService;
use Service\ChannelService\ChannelWxService;
use App\Model\BbcModel\Order;
use Service\DeclareService\PayDeclareService;
use Service\PayService\CashPayService;
use App\Model\BbcModel\OfflinePayReceive;

/**
 * 新生支付
 * @author chenshubo
 */
class Hnapay extends BaseService
{
    public $checktime = 200;
    
    /**
     * 扫码支付
     * @param int $cid
     * @param int $mn_sid
     * @param array $extra
     */
    public function scanPay(int $cid,int $mn_sid,int $mnid,array $param)
    {
        $store_type = $param['store_type'];
//        if( $store_type == MnUserService::TYPE_O2O ) {
//            $config = ChannelConfigService::instance()->getChannelConfig('hnapay_pay', $cid);
//        }
//        elseif( $store_type == MnUserService::TYPE_QZ ) {
//            $config = StoreConfigService::instance()->getConfig('hnapay_pay', $mn_sid);
//        }
        $config = StoreConfigService::instance()->getConfig('hnapay_pay', $mn_sid);
        if(empty($config)) {
            return Normal::returnCode(Normal::FAIL,"新生支付未配置");
        }
        $terminalInfoSN=$param['cash_register']['sn']??'';
        if(!$terminalInfoSN){
            return Normal::returnCode(Normal::FAIL,"新生支付收银台终端信息未配置");
        }
            
        $config['cid']  = $cid;
        $config['mnid'] = 4;
        if( !empty($param['auth_code']) ) {
            if( substr($param['auth_code'], 0,2) >= 20 ) {
                $authcodetype   = 'ALIPAY';
                $auth_user_pay_type= CashPayService::AUTH_USER_PAY_ALIPAY;
            }else{
                $authcodetype   = 'WECHATPAY';
                $auth_user_pay_type= CashPayService::AUTH_USER_PAY_WEIXIN;
            }
        }
        
        //获取回调
//        $callback_url = PayNotifyService::instance()->getChannelNotifyHost($cid);
//        if( empty($callback_url) ) {
//            return Normal::returnCode(Normal::FAIL,"新生支付回调地址未配置");
//        }
//        $path=request()->getRequestUri();   
//        $url=request()->url(); 
//        $callback_url=str_replace($path, '', $url);
        $uri=request()->getUri();   
        $callback_url=$uri->getScheme() . '://' . $uri->getHost();
        $uriport=$uri->getPort();
        if(!empty($uriport)&&!in_array((string)$uriport, ['80','443'])){
            $callback_url=$callback_url.':'.$uriport;
        }
        $noticeUrl = "{$callback_url}/cashpay/notify/hnapay/{$param['order_id']}";
        $ip=getIp()??'127.0.0.1';
        $order = [
            'merOrderId'        => $param['out_trade_no'], //商户交易订单号
            'displayName'       => $param['body'],//商户显示名称
            'goodsName'         => $param['body'],//商品名称
            'goodsCount'        => 1,//商品数量
            'goodsType'         => '',////商品类别tradeType=0004 货物贸易时必填服装-00 食品-01 电子产 品-02 箱包-03 日用品-04 保健品-05 化妆品-06 家电 -07tradeType=0013 旅游服务时必 填旅游签证-22
            'orderAmount'       => $param['total_fee'],//订单金额
            'orderCurrencyCode' => 'CNY',//订单币种
            'tradeType'         => '0002',////贸易类型0001-担保交易，0002-即时付 款，0003-跨境支付，0004-货物 贸易，0005-酒店住宿，0006-机 票旅游，0007-留学教育，0008- 国际会展，0009-国际会议， 0010-物流支付，0013-旅游服 务，0014-软件服务，0015-管理咨询，0016-设计咨询 注:境内订单上送 0002，如果是跨 境进口订单，需上送 0004-0016 对 应的贸易类型，否则订单无法用于 后续购付汇。Eg:进口商品上送 0004。
            'payType'           => '6',// //支付方式填写数字代码。1:B2C (B2C 直连到银行) 2:B2B(B2B 直连到银行)3:QUICK_PAY(快捷支付，该接口 为预支付申请) 4:QRCODE(扫码支付，商户被扫) 5:JS (公众号，小程序/服务 窗支付) 6:PAYCODE(刷卡支付，商户主 扫)7:APP(APP 支付) 8:H5 直连 9:预付费卡支付
            'orgCode'           => $authcodetype ??'',////目标机构资金代码填写机构英文代码,大写。参见 9.3 机构代码payType=1、2 或 3 时必填，支 持:CMB,ICBC...(具体参见银行 机构代码);payType=4 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信)，UNIONPAY(银联)，QQPAY (QQ 支付),JDPAY(京东支付); payType=5 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信);payType=6 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信);payType=7,8 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信);payType=9 时必填，支持: HNACARD(新生预付费卡);
            'payerAccount'      => $param['auth_code'],//付款方账户
            'returnUrl'         => $noticeUrl,//
            'noticeUrl'         => $noticeUrl,//
            'terminalInfo'      => $terminalInfoSN.'|'.$ip
        ];
        
        //前置仓
        $payreport_data = [];
        if( $store_type == MnUserService::TYPE_QZ && $param['is_order'] == 1 ) {
            $order['tradeType']     = '0004';
            $order['customerType']  = '1';
            $order['goodsType']     = '04';
            $order['customerName']  = $param['buyer']['truename'];
            $order['customerIdNo']  = $param['buyer']['idcard'];
            $order['customerTel']   = $param['buyer']['mobile'];
            $companyConfig = StoreConfigService::instance()->getConfig('e_company', $mn_sid);
            if(empty($companyConfig)) {
                return Normal::returnCode(Normal::FAIL,"电商平台未配置");
            }
            $payreport_data= [
                'cid'           => $cid,
                'company'       => $companyConfig,
                'payconfig'     => $config,
                'pay_type'      => 'hnapay',
                'pay_serial'    => '',
                'pay_sn'        => $param['out_trade_no']
            ];
        }
        
        //调用支付接口
        $initalRequest = json_encode($order,JSON_UNESCAPED_UNICODE);
        $client = (new HnapayApiClient($config));
        $result_call = $client->payOrder($order);
        if( $result_call['code'] != Normal::SUC ) {
            return $result_call;
        }
        
        $response = $result_call['data'];
        if( $response['content']['responseCode'] =='0000' ) 
        {
            if( $store_type == MnUserService::TYPE_QZ && $param['is_order'] == 1 ) {
                $payreport_data['pay_serial'] = $response['content']['dealId'];
                //PayDeclareService::instance()->publishMsg($payreport_data);
                //$result_call['data']['payreport_data']=$payreport_data;
            }
            return Normal::returnCode(Normal::SUC,"处理成功",[
                'transaction_id'    => $response['content']['dealId'],
                'initalRequest'     => $initalRequest,
                'initalResponse'    => json_encode($response,JSON_UNESCAPED_UNICODE),
                'auth_user_pay_type'=> $auth_user_pay_type,
                'payreport_data'    => $payreport_data,
                'pay_time'          => $response['content']['completeTime']?strtotime($response['content']['completeTime']):0
            ]);
        }
        else
        {
            $order['time']          = 0 ;
            $order['cid']           = $cid;
            $order['mn_sid']        = $mn_sid;
            $order['store_type']    = $param['store_type'];
            $order['initalRequest'] = $initalRequest;
            $order['auth_user_pay_type']=$auth_user_pay_type;
            $order['payreport_data']=$payreport_data;
            $order['is_order']      =$param['is_order'];
            return $this->checkHnOrderPay($order,$config);
        }
    }
    
    /**
     * 创建支付订单
     * @param int $cid
     * @param int $mn_sid
     * @param array $extra
     */
    public function userPay(int $cid,int $mn_sid,int $mnid,array $extra = [])
    {
        //渠道配置
        $config = ChannelConfigService::instance()->getChannelConfig('hnapay_pay', $cid);
        if(empty($config)) {
            return Normal::returnCode(Normal::FAIL,"新生支付未配置");
        }
        
        //支付配置
        $payConfig = ChannelWxService::instance()->queryWxConfig($cid);
        if(empty($payConfig)) {
            return Normal::returnCode(Normal::FAIL,"小程序支付未配置");
        }
        
        //在新生账号配置好的appid
        $appid = $payConfig['app_id'];
        
        //获取回调
        $callback_url = PayNotifyService::instance()->getChannelNotifyHost($cid);
        if( empty($callback_url) ) {
            return Normal::returnCode(Normal::FAIL,"新生支付回调地址未配置");
        }
        
        $noticeUrl = "http://{$callback_url}/webapi/pay/notify/{$cid}/{$mn_sid}/{$mnid}/hnapay/{$extra['order_no']}";
        
        //$ledger 分账标识
        $ledger = 0;//TODO 这里需要根据业务修改
        
        //预提交订单参数
        $order = [
            'merOrderId'        => $extra['order_no'], //商户交易订单号
            'displayName'       => $extra['remark'],//商户显示名称
            'goodsName'         => $extra['remark'],//商品名称
            'goodsCount'        => 1,//商品数量
            'goodsType'         => '',////商品类别tradeType=0004 货物贸易时必填服装-00 食品-01 电子产 品-02 箱包-03 日用品-04 保健品-05 化妆品-06 家电 -07tradeType=0013 旅游服务时必 填旅游签证-22
            'orderAmount'       => $extra['money'],//订单金额
            'orderCurrencyCode' => 'CNY',//订单币种
            'tradeType'         => '0002',////贸易类型0001-担保交易，0002-即时付 款，0003-跨境支付，0004-货物 贸易，0005-酒店住宿，0006-机 票旅游，0007-留学教育，0008- 国际会展，0009-国际会议， 0010-物流支付，0013-旅游服 务，0014-软件服务，0015-管理咨询，0016-设计咨询 注:境内订单上送 0002，如果是跨 境进口订单，需上送 0004-0016 对 应的贸易类型，否则订单无法用于 后续购付汇。Eg:进口商品上送 0004。
            'payType'           => '5',// //支付方式填写数字代码。1:B2C (B2C 直连到银行) 2:B2B(B2B 直连到银行)3:QUICK_PAY(快捷支付，该接口 为预支付申请) 4:QRCODE(扫码支付，商户被扫) 5:JS (公众号，小程序/服务 窗支付) 6:PAYCODE(刷卡支付，商户主 扫)7:APP(APP 支付) 8:H5 直连 9:预付费卡支付
            'orgCode'           => $authcodetype ??'',////目标机构资金代码填写机构英文代码,大写。参见 9.3 机构代码payType=1、2 或 3 时必填，支 持:CMB,ICBC...(具体参见银行 机构代码);payType=4 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信)，UNIONPAY(银联)，QQPAY (QQ 支付),JDPAY(京东支付); payType=5 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信);payType=6 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信);payType=7,8 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信);payType=9 时必填，支持: HNACARD(新生预付费卡);
            'returnUrl'         => $noticeUrl,//
            'noticeUrl'         => $noticeUrl,//
            'orgCode'           => 'WECHATPAY',
            'payerAccount'      => $extra['open_id'] ?? '',
            'reserve2'          => $appid, //$appid
            //'shareFlag'         => $ledger,//分账标识
        ];
        
        $client = (new HnapayApiClient($config));
        $result = $client->payOrder($order);
        if( $result['code'] != Normal::SUC ) {
            return $result;
        }
        
        $payInfo    = $result['data']['payInfo']['payInfo'];
        $str        = ltrim($payInfo,'{');
        $str        = rtrim($str,'}');
        $str        = str_replace(",","&",$str);
        parse_str($str,$strArr);
        return Normal::returnCode(Normal::SUC,"处理成功",[
            'payInfo'       => $strArr,
            'payRequest'    => json_encode($order,JSON_UNESCAPED_UNICODE),
            'payResponse'   => json_encode($result['data'],JSON_UNESCAPED_UNICODE),
        ]);
    }
    
    /**
     * 查询新生支付
     * @param array $param
     */
    public function checkHnOrderPay( array $param = [],array $payconfig=[] )
    {
        sleep(5);
        $param['time'] += 5;
        
        $body=[
            'queryType'=>'1',
            'orderType'=>'1',
            'oldMerOrderId'=>$param['merOrderId']
        ];
        
        //调用查询支付订单状态接口
        $client = (new HnapayApiClient($payconfig));
        $result_query = $client->queryPay($body);
        if( $result_query['code'] != Normal::SUC ) {
            return $result_query;
        }
        $payreport_data=$param['payreport_data'];
        $response = $result_query['data'];
        if( isset($response['content']['orderInfo']) && $response['content']['orderInfo'][0]['status'] == 1 ) {
            if( $param['store_type'] == MnUserService::TYPE_QZ && $param['is_order'] == 1 ) {
                
                $payreport_data['pay_serial'] = $response['content']['orderInfo'][0]['dealId'];
                //PayDeclareService::instance()->publishMsg($payreport_data);
            }
            return Normal::returnCode(Normal::SUC,"处理成功",[
                'transaction_id'    => $response['content']['orderInfo'][0]['dealId'],
                'initalRequest'     => $param['initalRequest'],
                'initalResponse'    => json_encode($response,JSON_UNESCAPED_UNICODE),
                'auth_user_pay_type'=>$param['auth_user_pay_type'],
                'payreport_data'    =>$payreport_data,
                'pay_time'          => $response['content']['orderInfo'][0]['completeTime']?strtotime($response['content']['orderInfo'][0]['completeTime']):0
            ]);
        }
        
        if( isset($response['content']['orderInfo']) && $response['content']['orderInfo'][0]['status'] == 2 ) {
            return Normal::returnCode(Normal::FAIL,"新生支付交易超时,请重试");
        }
        
        if ( $param['time'] >= $this->checktime ) {
            return Normal::returnCode(Normal::FAIL,"新生支付交易超时,请重试,已重试40次!");
        }
        
        return $this->checkHnOrderPay($param,$payconfig);
    }
    
    /**
     *  解析body内容
     * @param $body
     */
    public function getNotify($body)
    {
        //解析回调body内容
    }
    
    public function scanPayRefund(int $cid,int $mn_sid,int $mnid,array $param){
        $store_type = $param['store_type'];
//        if( $store_type == MnUserService::TYPE_O2O ) {
//            $config = ChannelConfigService::instance()->getChannelConfig('hnapay_pay', $cid);
//        }
//        elseif( $store_type == MnUserService::TYPE_QZ ) {
//            $config = StoreConfigService::instance()->getConfig('hnapay_pay', $mn_sid);
//        }
        $config = StoreConfigService::instance()->getConfig('hnapay_pay', $mn_sid);
        if(empty($config)) {
            return Normal::returnCode(Normal::FAIL,"新生支付未配置");
        }
        
        //获取回调
//        $callback_url = PayNotifyService::instance()->getChannelNotifyHost($cid);
//        if( empty($callback_url) ) {
//            return Normal::returnCode(Normal::FAIL,"新生支付回调地址未配置");
//        }
        
//        $path=request()->getRequestUri();   
//        $url=request()->url(); 
//        $callback_url=str_replace($path, '', $url);
        $uri=request()->getUri();   
        $callback_url=$uri->getScheme() . '://' . $uri->getHost();
        $uriport=$uri->getPort();
        if(!empty($uriport)&&!in_array((string)$uriport, ['80','443'])){
            $callback_url=$callback_url.':'.$uriport;
        }
        $noticeUrl = "{$callback_url}/cashpay/notify/hnapay/{$param['order_id']}";
        $order_data = [
            'merOrderId' => (string)$param['out_refund_no'],
            'oldMerOrderId' =>(string)$param['out_trade_no'],
            'amount' => (int)(round($param['refund_fee']*100,2)),
            'currency' => 'CNY',
            'noticeUrl' => $noticeUrl,
        ];
        $client = (new HnapayApiClient($config));
        $result_call = $client->returnOrder($order_data);
        if( $result_call['code'] != Normal::SUC ) {
            return $result_call;
        }
        $response = $result_call['data'];
        if( $response['content']['responseCode'] =='0000' ) {
            if($response['content']['status']==1){
                return Normal::returnCode(Normal::SUC,'退款成功',$response);
            }elseif($response['content']['status']==2){
                return Normal::returnCode(Normal::FAIL,'退款失败:'.$response['content']['responseDesc'],$response);
            }else{
                $order_data['time']=0;
                return $this->checkReturnPay($order_data,$config);
            }
        }elseif($response['content']['responseCode']=='0001'){
            $order_data['time']=0;
            return $this->checkReturnPay($order_data,$config);
        }else{
            return Normal::returnCode(Normal::FAIL,'退款失败:'.$response['content']['responseDesc'],$response);
        }
    }
    
    /**
     * 查询退款
     * @param array $param
     * @param array $payconfig
     * @return type
     */
    public function checkReturnPay(array $param = [],array $payconfig=[]) {
        sleep(5);
        $param['time'] += 5;
        $order=[
            'queryType'=>'1',
            'orderType'=>'2',
            'oldMerOrderId'=>$param['merOrderId']
        ];
        
        //调用查询支付订单状态接口
        $client = (new HnapayApiClient($payconfig));
        $result_query = $client->queryPay($order);
        if( $result_query['code'] != Normal::SUC ) {
            return $result_query;
        }
        $response = $result_query['data'];
        //if(isset($response['content']['orderInfo'])&&$response['content']['orderInfo'][0]['status']==1){由于新生退款蛮,更改为只要提交就成功,不判断状态
        if(isset($response['content']['orderInfo'])){
            return Normal::returnCode(Normal::SUC,'退款成功',$response);
        }else{
            if($param['time']>=$this->checktime){
                return Normal::returnCode(Normal::FAIL,'超时失败',$response);
           }else{
                return $this->checkReturnPay($param,$payconfig);
           }
        }
//        if( isset($response['content']['orderInfo']) && $response['content']['orderInfo'][0]['status'] == 2 ) {
//            return Normal::returnCode(Normal::FAIL,"退款失败",$response);
//        }
//        
//        if ( $param['time'] >= $this->checktime ) {
//            return Normal::returnCode(Normal::FAIL,"新生支付交易超时,请重试,已重试40次!");
//        }
        
    }
    
    /**
     * 收银异步通知,不做处理直接记录数据库,业务在发起时已经同步处理 
     * @param type $msg
     */
    public function cashNotify($msg) {
        $datajson=base64_decode($msg); 
        $data= json_decode($datajson,true);
        OfflinePayReceive::instance()->add([
            'cd'=>time(),
            'cid'=>0,
            'ordersn'=>$data['content']['merOrderId']??'',
            'pay_rece_sn'=>$data['content']['refundOrderNo']??'',
            'msg'=>$data['content']['responseDesc']??'',
            'content'=>$datajson
        ]);
    }
}
